package lianxi11;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.stream.Collectors;
import java.util.stream.Stream;


public class BestPriceFinder {

	
	private final List<Shop> shops =Arrays.asList(new Shop("BestPrice"),
			  new Shop("LetsSaveBig"),
			  new Shop("MyFavoriteShop"),
			  new Shop("BuyItAll"),
			  new Shop("ShopEasy")
			  );
	
	private final Executor executor = Executors.newFixedThreadPool(shops.size(), new ThreadFactory() {
		
		@Override
		public Thread newThread(Runnable r) {
			Thread t =new Thread(r);
			t.setDaemon(true);
			return t;
		}
	});
	
	public List<String> findPricesSequential(String product){
		return shops.stream()
					.map(shop -> shop.getPrice(product))
					.map(Quote::parse)
					.map(Discount::applyDiscount)
					.collect(Collectors.toList());
	}
	
	
	public List<String> findPricesSequentialParaller(String product){
	
		return shops.parallelStream()
				.map(shop -> shop.getPrice(product))
				.map(Quote::parse)
				.map(Discount::applyDiscount)
				.collect(Collectors.toList());
	}

	public List<String> findPricesFuture(String product){
		  List<CompletableFuture<String>> priceFutures =
				  			findPricesStream(product).collect(Collectors.toList());
		  return priceFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
	}
	
	
	public Stream<CompletableFuture<String>> findPricesStream (String product){
		Stream<CompletableFuture<String>> stream = shops.stream().map(shop -> CompletableFuture.supplyAsync(()->shop.getPrice(product),executor))
					  .map(future -> future.thenApply(Quote::parse))
					  .map(future -> future.thenCompose(quote -> 
					  CompletableFuture.supplyAsync(()-> Discount.applyDiscount(quote),executor)));
		return  stream;
	}
	
	public void printPricesStream(String product){
		long start =System.nanoTime();
		CompletableFuture[] futures = findPricesStream(product)
									  .map(f -> f.thenAccept(s ->System.out.println(s+
											" done in" +((System.nanoTime() -start)/1_000_000)+"msecs"  )))
									  .toArray(size -> new CompletableFuture[size]);
		CompletableFuture.allOf(futures).join();
		System.out.println("All shops have now responded in "+ ((System.nanoTime() -start)/1_000_1000)+"msecs");
		
		
		
	}
	
}
